/***************************************************************************
 *   Copyleft 2008-2009 by												   *
 *	 Iwanicki Krzysztof													   *
 *   <gamma.mini.pw.edu.pl/~iwanickik>									   *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 ***************************************************************************/
#include "./vSetupDialog.h"
#include "../../Macros/vLogMacros.h"
#include <stdio.h>


namespace Vendetta {
	HINSTANCE vSetupDialog::mhInstance;
	vSetupDialog* vSetupDialog::mpSetupDialog = vNull;

	vSetupDialog::vSetupDialog()
		: vAbstractModalDialog(vNull) {
			mhInstance = ::GetModuleHandle(vNull);
			mpDeviceInfo = vNull;
			mScreenPanel = true;
			mShouldSaveConfig = false;
			vSetupDialog::mpSetupDialog = this;
	}
	
	vSetupDialog::vSetupDialog(HINSTANCE hInstance, HWND hWndOwner)
		: vAbstractModalDialog(hWndOwner) {
		mhInstance = hInstance;
		mpDeviceInfo = vNull;
		mScreenPanel = true;
		mShouldSaveConfig = false;
		vSetupDialog::mpSetupDialog = this;
	}

	vSetupDialog::~vSetupDialog() {
		vSetupDialog::mpSetupDialog = vNull;
	}

	vInt vSetupDialog::Exec(vDeviceInfo* devInfoPtr) {
		if (!devInfoPtr) {
			return 0;
		}
		mpDeviceInfo = devInfoPtr;
		return (vInt) ::DialogBox(mhInstance, MAKEINTRESOURCE(IDD_SETUP_DIALOG), 
			mhOwner, (DLGPROC) dialogProc);
	}

	vDeviceInfo* vSetupDialog::DeviceInfoPtr() {
		return mpDeviceInfo;
	}

	vBool vSetupDialog::SaveConfig() const {
		return mShouldSaveConfig;
	}

	LRESULT CALLBACK vSetupDialog::dialogProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) {
		static HBITMAP mhMemBmp, hProcNorm, hProcHov, hScrNorm, hScrHov, hOldBmp;
		static eMenuItemState eIsInProc = VMIS_SELECTED, eIsInScr = VMIS_NORMAL;
		static HDC g_hDCMem, hBmpDC, hBmp2DC;
		static vBool bScreen = true;
		static HWND hMenu;
		RECT rect;

		
		switch(message)	{
		case WM_INITDIALOG: {
				::InitCommonControls();
				hMenu = ::GetDlgItem(hDlg, IDC_MENU_STATIC);
				::GetWindowRect(hDlg, &rect);
				::SetWindowLong(hMenu, GWL_EXSTYLE, SS_OWNERDRAW);
				::SetWindowLong(hDlg, GWL_EXSTYLE, WS_CLIPSIBLINGS | WS_CLIPCHILDREN);
				hProcHov = ::LoadBitmap(mhInstance, MAKEINTRESOURCE(IDB_PROC_HOV_BMP));
				hProcNorm = ::LoadBitmap(mhInstance, MAKEINTRESOURCE(IDB_PROC_NORM_BMP));
				hScrNorm = ::LoadBitmap(mhInstance, MAKEINTRESOURCE(IDB_SCR_NORM_BMP));
				hScrHov = ::LoadBitmap(mhInstance, MAKEINTRESOURCE(IDB_SCR_HOV_BMP));
				HDC hDC = ::GetDC(hMenu);
				hBmpDC = ::CreateCompatibleDC(hDC);
				hBmp2DC = ::CreateCompatibleDC(hDC);
				ReleaseDC(hDlg, hDC);
				vSetupDialog::mpSetupDialog->initFields(hDlg);
			}
			break;
		case WM_LBUTTONDOWN:
			vSetupDialog::mpSetupDialog->onLeftButtonDown(&eIsInProc, &eIsInScr, hDlg, wParam, lParam);
			break;
		case WM_MOUSEMOVE:
			vSetupDialog::mpSetupDialog->onMouseMove(&eIsInProc, &eIsInScr, hDlg, wParam, lParam);
			break;
		case WM_CLOSE:
			::EndDialog(hDlg, 0);
			break;
		case WM_DESTROY:
			::DeleteObject(hProcHov);
			::DeleteObject(hProcNorm);
			::DeleteObject(hScrHov);
			::DeleteObject(hScrNorm);
			::DeleteDC(hBmpDC);
			::DeleteDC(hBmp2DC);
			break;
		case WM_DRAWITEM: {
				LPDRAWITEMSTRUCT pdis;
				RECT rectDrag, rectfrom;
				HDC hDC;
				HWND hDrawItem;

				pdis = (LPDRAWITEMSTRUCT) lParam;
				hDC = pdis->hDC;
				hDrawItem = pdis->hwndItem;

				if (eIsInProc != VMIS_NORMAL) {
					::SelectObject(hBmpDC, hProcHov);
				} else {
					::SelectObject(hBmpDC, hProcNorm);
				}
				if (eIsInScr != VMIS_NORMAL) {
					::SelectObject(hBmp2DC, hScrHov);
				} else {
					::SelectObject(hBmp2DC, hScrNorm);
				}
				GetClientRect(hDrawItem, &rectDrag);
				GetWindowRect(hDrawItem, &rectfrom);
				::FillRect(hDC, &rectDrag, (HBRUSH) GetStockObject(WHITE_BRUSH));
				::SelectObject(hDC, GetStockObject(HOLLOW_BRUSH));
				::SelectObject(hDC, GetStockObject(BLACK_PEN));
				::Rectangle(hDC, rectDrag.left, rectDrag.top, rectDrag.right, rectDrag.bottom);
				::BitBlt(hDC, rectDrag.left + 8, rectDrag.top + 13, rectDrag.right, rectDrag.bottom, 
					hBmpDC, 0, 0, SRCCOPY);
				::BitBlt(hDC, rectDrag.left + 8, rectDrag.top + 92 + 26, rectDrag.right, rectDrag.bottom, 
					hBmp2DC, 0, 0, SRCCOPY);
			}
			break;
		case WM_COMMAND:
			vSetupDialog::mpSetupDialog->onCommand(hDlg, wParam, lParam);
			break;
		}
		return false;
	}

	vVoid vSetupDialog::initFields(HWND hDlg) {
		fillResolution(hDlg, true, true);
		fillParam(hDlg, IDC_COLOR_CBOX, "ColorDepth");
		fillParam(hDlg, IDC_FREQ_CBOX, "Frequency");
	}

	vVoid vSetupDialog::refresh(HWND hDlg) {
		clearComboBox(hDlg, IDC_COLOR_CBOX);
		clearComboBox(hDlg, IDC_FREQ_CBOX);
		if (mpDeviceInfo) {
			mpDeviceInfo->Refresh();
		}
		fillParam(hDlg, IDC_COLOR_CBOX, "ColorDepth");
		fillParam(hDlg, IDC_FREQ_CBOX, "Frequency");
	}

	vBool vSetupDialog::isValid() {
		for (vUInt uiPos = 0; uiPos < mpDeviceInfo->mValidOptions.Size(); uiPos++) {
			vPair<vString, vConfigOption> pair = mpDeviceInfo->mValidOptions.Element(uiPos);
			if (pair.Second.CurrentOption.IsEmpty() || pair.Second.CurrentOption.IsEqual("")) {
				return false;
			}
		}
		return mpDeviceInfo->IsValid();
	}

	vVoid vSetupDialog::onMouseMove(vSetupDialog::eMenuItemState *eIsInProc, 
		vSetupDialog::eMenuItemState *eIsInScr, HWND hDlg, WPARAM wParam, LPARAM lParam) {
		vPoint q;
		vRect rect;

		q.x = ((short) LOWORD (lParam));
		q.y = ((short) HIWORD (lParam));

		if (q.x > 15 && q.x < (15 + 92)) {
			if (q.y > 181 && q.y < (181 + 92)) {
				*eIsInProc = *eIsInProc == VMIS_SELECTED ? VMIS_SELECTED : VMIS_HOVER;
			} else {
				*eIsInProc = *eIsInProc == VMIS_SELECTED ? VMIS_SELECTED : VMIS_NORMAL;
			}
			if (q.y > (181 + 92 + 13) && q.y < (181 + 92 + 13 + 92)) {
				*eIsInScr = *eIsInScr == VMIS_SELECTED ? VMIS_SELECTED : VMIS_HOVER;
			} else {
				*eIsInScr = *eIsInScr == VMIS_SELECTED ? VMIS_SELECTED : VMIS_NORMAL;
			}
		} else {
			*eIsInProc = *eIsInProc == VMIS_SELECTED ? VMIS_SELECTED : VMIS_NORMAL;
			*eIsInScr = *eIsInScr == VMIS_SELECTED ? VMIS_SELECTED : VMIS_NORMAL;
		}

		::GetClientRect(hDlg, &rect);
		::InvalidateRect(hDlg, &rect, false);
	}

	vVoid vSetupDialog::onLeftButtonDown(vSetupDialog::eMenuItemState *eIsInProc, 
		vSetupDialog::eMenuItemState *eIsInScr, HWND hDlg, WPARAM wParam, LPARAM lParam) {
		vPoint q;
		vRect rect;

		q.x = ((short) LOWORD (lParam));
		q.y = ((short) HIWORD (lParam));

		if (q.x > 15 && q.x < (15 + 92)) {
			if (q.y > 181 && q.y < (181 + 92)) {
				*eIsInProc = VMIS_SELECTED;
				*eIsInScr = VMIS_NORMAL;
				vSetupDialog::mpSetupDialog->setParams(hDlg, true);
			}
			if (q.y > (181 + 92 + 13) && q.y < (181 + 92 + 13 + 92)) {
				*eIsInScr = VMIS_SELECTED;
				*eIsInProc = VMIS_NORMAL;
				vSetupDialog::mpSetupDialog->setParams(hDlg, false);
			}
		}
		::GetClientRect(hDlg, &rect);
		::InvalidateRect(hDlg, &rect, false);
	}

	vVoid vSetupDialog::onCommand(HWND hDlg, WPARAM wParam, LPARAM lParam) {
		switch (LOWORD (wParam)) {
			case IDOK:
				if (isValid()) {
					mShouldSaveConfig = !::IsDlgButtonChecked(hDlg, IDC_SHOW_CHBX) ? false : true;
					vSetupDialog::mpSetupDialog->mpDeviceInfo = vNull;
					::EndDialog(hDlg, 1);
				}
				break;
			case IDCANCEL:
				vSetupDialog::mpSetupDialog->mpDeviceInfo = vNull;
				::EndDialog(hDlg, 0);
				break;
			case IDC_VIDEO_CBOX:
				if (HIWORD (wParam) == CBN_SELCHANGE) {
					if (vSetupDialog::mpSetupDialog->mScreenPanel) {
						vSetupDialog::mpSetupDialog->onVideoChanged(hDlg, wParam, lParam);
					} else {
						vSetupDialog::mpSetupDialog->onFullScreenChanged(hDlg, wParam, lParam);
					}
				}
				break;
			case IDC_COLOR_CBOX:
				if (HIWORD (wParam) == CBN_SELCHANGE) {
					if (vSetupDialog::mpSetupDialog->mScreenPanel) {
						vSetupDialog::mpSetupDialog->onColorChanged(hDlg, wParam, lParam);
					} else {
						vSetupDialog::mpSetupDialog->onVSynChanged(hDlg, wParam, lParam);
					}
				}
				break;
			case IDC_FREQ_CBOX:
				if (HIWORD (wParam) == CBN_SELCHANGE) {
					if (vSetupDialog::mpSetupDialog->mScreenPanel) {
						vSetupDialog::mpSetupDialog->onFreqChanged(hDlg, wParam, lParam);
					} else {
						vSetupDialog::mpSetupDialog->onGPUChanged(hDlg, wParam, lParam);
					}
				}
				break;
			default:
				break;
		}
	}

	vVoid vSetupDialog::onVideoChanged(HWND hDlg, WPARAM wParam, LPARAM lParam) {
		vInt index = (vInt) ::SendMessage((HWND) lParam, CB_GETCURSEL, 0, 0);
		vInt uiSize = (vInt) vSetupDialog::mpSetupDialog->mpDeviceInfo->mValidOptions["VideoMode"].AvailableOptions.Size();
		if (index < uiSize && index >= 0) {
			vSetupDialog::mpSetupDialog->mpDeviceInfo->mValidOptions["VideoMode"].CurrentOption = vSetupDialog::mpSetupDialog->mpDeviceInfo->mValidOptions["VideoMode"].AvailableOptions[index];
			vSetupDialog::mpSetupDialog->refresh(hDlg);
		}
	}

	vVoid vSetupDialog::onColorChanged(HWND hDlg, WPARAM wParam, LPARAM lParam) {
		vInt index = (vInt) ::SendMessage((HWND) lParam, CB_GETCURSEL, 0, 0);
		vInt uiSize = (vInt) vSetupDialog::mpSetupDialog->mpDeviceInfo->mValidOptions["ColorDepth"].AvailableOptions.Size();
		if (index < uiSize && index >= 0) {
			vSetupDialog::mpSetupDialog->mpDeviceInfo->mValidOptions["ColorDepth"].CurrentOption = vSetupDialog::mpSetupDialog->mpDeviceInfo->mValidOptions["ColorDepth"].AvailableOptions[index];
		}
	}

	vVoid vSetupDialog::onFreqChanged(HWND hDlg, WPARAM wParam, LPARAM lParam) {
		vInt index = (vInt) ::SendMessage((HWND) lParam, CB_GETCURSEL, 0, 0);
		vInt uiSize = (vInt) vSetupDialog::mpSetupDialog->mpDeviceInfo->mValidOptions["Frequency"].AvailableOptions.Size();
		if (index < uiSize && index >= 0) {
			vSetupDialog::mpSetupDialog->mpDeviceInfo->mValidOptions["Frequency"].CurrentOption = vSetupDialog::mpSetupDialog->mpDeviceInfo->mValidOptions["Frequency"].AvailableOptions[index];
		}
	}

	vVoid vSetupDialog::onFullScreenChanged(HWND hDlg, WPARAM wParam, LPARAM lParam) {
		vInt index = (vInt) ::SendMessage((HWND) lParam, CB_GETCURSEL, 0, 0);
		vInt uiSize = (vInt) vSetupDialog::mpSetupDialog->mpDeviceInfo->mValidOptions["FullScreen"].AvailableOptions.Size();
		if (index < uiSize && index >= 0) {
			vSetupDialog::mpSetupDialog->mpDeviceInfo->mValidOptions["FullScreen"].CurrentOption = vSetupDialog::mpSetupDialog->mpDeviceInfo->mValidOptions["FullScreen"].AvailableOptions[index];
		}
	}

	vVoid vSetupDialog::onVSynChanged(HWND hDlg, WPARAM wParam, LPARAM lParam) {
		vInt index = (vInt) ::SendMessage((HWND) lParam, CB_GETCURSEL, 0, 0);
		vInt uiSize = (vInt) vSetupDialog::mpSetupDialog->mpDeviceInfo->mValidOptions["VSync"].AvailableOptions.Size();
		if (index < uiSize && index >= 0) {
			vSetupDialog::mpSetupDialog->mpDeviceInfo->mValidOptions["VSync"].CurrentOption = vSetupDialog::mpSetupDialog->mpDeviceInfo->mValidOptions["VSync"].AvailableOptions[index];
		}
	}

	vVoid vSetupDialog::onGPUChanged(HWND hDlg, WPARAM wParam, LPARAM lParam) {
		vInt index = (vInt) ::SendMessage((HWND) lParam, CB_GETCURSEL, 0, 0);
		vInt uiSize = (vInt) vSetupDialog::mpSetupDialog->mpDeviceInfo->mValidOptions["GPUGeometry"].AvailableOptions.Size();
		if (index < uiSize && index >= 0) {
			vSetupDialog::mpSetupDialog->mpDeviceInfo->mValidOptions["GPUGeometry"].CurrentOption = vSetupDialog::mpSetupDialog->mpDeviceInfo->mValidOptions["GPUGeometry"].AvailableOptions[index];
		}
	}

	vVoid vSetupDialog::fillResolution(HWND hDlg, vBool bFirstTime, vBool bRefresh) {
		HWND hCombo = ::GetDlgItem(hDlg, IDC_VIDEO_CBOX);
		vConfigOption opt = mpDeviceInfo->mValidOptions["VideoMode"];
		vUInt uiPos = 0;
		for (; uiPos < opt.AvailableOptions.Size(); uiPos++) {
			::SendMessage(hCombo, CB_INSERTSTRING, -1, (LPARAM) opt.AvailableOptions[uiPos].ToConstCharPtr());
		}
		if (bFirstTime) {
			if (opt.AvailableOptions.Size() > 0) {
				::SendMessage(hCombo, CB_SETCURSEL, (WPARAM) (uiPos - 1), 0);
				mpDeviceInfo->mValidOptions["VideoMode"].CurrentOption = opt.AvailableOptions[uiPos - 1];
			} else {
				mpDeviceInfo->mValidOptions["VideoMode"].CurrentOption = "";
			}
		} else {
			if (CB_ERR == ::SendMessage(hCombo, CB_SELECTSTRING, -1, 
				(LPARAM) mpDeviceInfo->mValidOptions["VideoMode"].CurrentOption.ToConstCharPtr())) {
					mpDeviceInfo->mValidOptions["VideoMode"].CurrentOption = "";
			}
		}
		if (bRefresh) {
			mpDeviceInfo->Refresh();
		}
	}

	vVoid vSetupDialog::fillParam(HWND hDlg, vInt iParID, const vString& paramName) {
		HWND hCombo = ::GetDlgItem(hDlg, iParID);
		vConfigOption opt = mpDeviceInfo->mValidOptions[paramName];
		vUInt uiPos = 0;

		if (opt.IsReadOnly) {
			::SendMessage(hCombo, CB_INSERTSTRING, -1, (LPARAM) opt.CurrentOption.ToConstCharPtr());
		} else {
			for (; uiPos < opt.AvailableOptions.Size(); uiPos++) {
				::SendMessage(hCombo, CB_INSERTSTRING, -1, (LPARAM) opt.AvailableOptions[uiPos].ToConstCharPtr());
			}
		}
		if (CB_ERR == ::SendMessage(hCombo, CB_SELECTSTRING, -1, 
			(LPARAM) mpDeviceInfo->mValidOptions[paramName].CurrentOption.ToConstCharPtr())) {
		}
	}

	vVoid vSetupDialog::setParams(HWND hDlg, vBool bScreen) {
		mScreenPanel = bScreen;
		////Combo Boxes
		clearComboBox(hDlg, IDC_VIDEO_CBOX);
		clearComboBox(hDlg, IDC_COLOR_CBOX);
		clearComboBox(hDlg, IDC_FREQ_CBOX);

		if (mScreenPanel) {
			//Static Groups
			::SetDlgItemText(hDlg, IDC_VM_GROUP, "Video Mode");
			::SetDlgItemText(hDlg, IDC_COL_GROUP, "Color Depth");
			::SetDlgItemText(hDlg, IDC_FREQ_GROUP, "Frequency");
			fillResolution(hDlg, false, false);
			fillParam(hDlg, IDC_COLOR_CBOX, "ColorDepth");
			fillParam(hDlg, IDC_FREQ_CBOX, "Frequency");
		} else {
			//Static Groups
			::SetDlgItemText(hDlg, IDC_VM_GROUP, "Full Screen");
			::SetDlgItemText(hDlg, IDC_COL_GROUP, "VSync");
			::SetDlgItemText(hDlg, IDC_FREQ_GROUP, "GPU Geometry");
			fillParam(hDlg, IDC_VIDEO_CBOX, "FullScreen");
			fillParam(hDlg, IDC_COLOR_CBOX, "VSync");
			fillParam(hDlg, IDC_FREQ_CBOX, "GPUGeometry");
		}
	}

	vVoid vSetupDialog::clearComboBox(HWND hDlg, vInt iId) {
		HWND hComboBox = ::GetDlgItem(hDlg, iId);
		::SendMessage(hComboBox, CB_RESETCONTENT, 0, 0);
	}
}